package com.flyduck.security.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.flyduck.security.dto.AppUser;
import com.flyduck.security.util.JwtTokenUtil;
import com.flyduck.security.util.ResponseUtil;
import com.flyduck.security.vo.ApiResult;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.CollectionUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p></p>
 *
 * @author flyduck 2021/7/7
 * @version V1.0
 * @modificationHistory=========================逻辑或功能性重大变更记录
 * @modify by user: flyduck 2021/7/7
 * @modify by reason:{方法名}:{原因}
 **/
public class AppAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private static final String USERNAME_KEY = "userName";
    private static final String PASSWORD_KEY = "password";

    private AuthenticationManager authenticationManager;

    public AppAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
        this.setPostOnly(true);
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", HttpMethod.POST.name()));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        String userName;
        String password;
        if (MediaType.APPLICATION_JSON_UTF8_VALUE.equalsIgnoreCase(request.getContentType())
                || MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(request.getContentType())) {
            // application/json 请求
            ObjectMapper mapper = new ObjectMapper();
            try {
                Map<String, String> authenticationBean = mapper.readValue(request.getInputStream(), Map.class);
                userName = authenticationBean.get(USERNAME_KEY);
                password = authenticationBean.get(PASSWORD_KEY);
            } catch (Exception e) {
                userName = "";
                password = "";
            }
        } else {
            // application/x-www-form-urlencoded 等非json的请求
            userName = request.getParameter(USERNAME_KEY);
            password = request.getParameter(PASSWORD_KEY);
        }

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userName, password);

        return authenticationManager.authenticate(authenticationToken);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        AppUser user = (AppUser) authResult.getPrincipal();
        List<String> authorities = new ArrayList<>();
        if (!CollectionUtils.isEmpty(user.getAuthorities())) {
            authorities = user.getAuthorities().stream().map(item -> item.getAuthority()).collect(Collectors.toList());
        }
        String token = JwtTokenUtil.createToken(user.getId(), user.getUsername(), authorities);
        ResponseUtil.out(response, ApiResult.success(token));
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        ResponseUtil.out(response, ApiResult.validateFailed("用户名或者密码错误"));
    }
}
